﻿using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using Medianamik.Core.Sugar;
using System.Collections.Specialized;

namespace Medianamik.Core
{
    public enum NodeTypePropertyRelationship
    {
        Default = 0,
        OneToMany = 1,
        ManyToOne = 2,
        ManyToMany
    }

    /// <summary>
    /// Classe représantant une Property d'un Type Medianamik
    /// </summary>
    [DebuggerDisplay("{Name}")]
    public class NodeTypeProperty : IProperty
    {
        //TODO: Ajouter les méthodes pour gérer les flags

        #region .ctors

        internal NodeTypeProperty(Guid pID
            , string pName
            , short? pMaxLength
            , short? pMinLength
            , Guid pTypeID
            , bool pHaveTooltip
            , bool pIsLanguageNeutral
            , bool pAllowsNull
            , bool pIsUnique
            , Regex pValidationRegex
            , string pGroupName
            , Guid? pMedianamikControlID
            , MedianamikControlInfo? pMedianamikControlSettings
            , Guid pDataTypeId
            , Guid? pPrimaryTypeID
            , Guid? pPrimaryPropertyID
            , Guid? pPrimaryMedianamikControlID
            , MedianamikControlInfo? pPrimaryMedianamikControlSettings
            , Guid? pPrimaryDataTypeId)
        {
            //TODO: Modifier le DataType pour l'objet plutôt que seulement l'ID
            //TODO: Terminer la validation des paremètres d'initialisation
            //TODO: Vérifier le DataType pour valider le Length

            ID = pID;
            Name = pName;
            MinLength = pMinLength;
            MaxLength = pMaxLength;
            HaveTooltip = pHaveTooltip;
            IsLanguageNeutral = pIsLanguageNeutral;
            IsRequired = pAllowsNull;
            IsUnique = pIsUnique;
            ValidationRegex = pValidationRegex;
            MedianamikControlID = pMedianamikControlID;
            GroupName = pGroupName ?? String.Empty;
            TypeID = pTypeID;
            if (pMedianamikControlSettings.HasValue) { MedianamikControlInfo = pMedianamikControlSettings.Value; }
            _dataTypeId = pDataTypeId;
            PrimaryTypeID = pPrimaryTypeID;
            PrimaryPropertyID = pPrimaryPropertyID;
            PrimaryMedianamikControlID = pPrimaryMedianamikControlID;
            if (pPrimaryMedianamikControlSettings.HasValue) { PrimaryMedianamikControlInfo = pPrimaryMedianamikControlSettings.Value; }
            _primaryDataTypeId = pPrimaryDataTypeId;
            IsGenerated = true;
        }

        internal NodeTypeProperty(string pName
            , short? pMaxLength
            , short? pMinLength
            , Guid pTypeID
            , bool pHaveTooltip
            , bool pIsLanguageNeutral
            , bool pAllowsNull
            , bool pIsUnique
            , Regex pValidationRegex
            , string pGroupName
            , Guid? pMedianamikControlID
            , MedianamikControlInfo? pMedianamikControlSettings
            , Guid pDataTypeId
            , Guid? pPrimaryTypeID
            , Guid? pPrimaryPropertyID
            , Guid? pPrimaryMedianamikControlID
            , MedianamikControlInfo? pPrimaryMedianamikControlSettings
            , Guid? pPrimaryDataTypeId
            , Guid? pTreeRootNodeId)
            : this(Guid.NewGuid()
            , pName
            , pMaxLength
            , pMinLength
            , pTypeID
            , pHaveTooltip
            , pIsLanguageNeutral
            , pAllowsNull
            , pIsUnique
            , pValidationRegex
            , pGroupName
            , pMedianamikControlID
            , pMedianamikControlSettings
            , pDataTypeId
            , pPrimaryTypeID
            , pPrimaryPropertyID
            , pPrimaryMedianamikControlID
            , pPrimaryMedianamikControlSettings
            , pPrimaryDataTypeId)
        {
            IsNew = true;
        }

        internal NodeTypeProperty(Guid pID
            , string pName
            , short? pMaxLength
            , short? pMinLength
            , Guid pTypeID
            , bool pHaveTooltip
            , bool pIsLanguageNeutral
            , bool pAllowsNull
            , bool pIsUnique
            , Regex pValidationRegex
            , string pGroupName
            , Guid? pMedianamikControlID
            , MedianamikControlInfo? pMedianamikControlSettings
            , Guid pDataTypeId)
            : this(pID
            , pName
            , pMaxLength
            , pMinLength
            , pTypeID
            , pHaveTooltip
            , pIsLanguageNeutral
            , pAllowsNull
            , pIsUnique
            , pValidationRegex
            , pGroupName
            , pMedianamikControlID
            , pMedianamikControlSettings
            , pDataTypeId
            , null, null, null, null, null)

        { }

        internal NodeTypeProperty(string pName
            , short? pMaxLength
            , short? pMinLength
            , Guid pTypeID
            , bool pHaveTooltip
            , bool pIsLanguageNeutral
            , bool pAllowsNull
            , bool pIsUnique
            , Regex pValidationRegex
            , string pGroupName
            , Guid? pMedianamikControlID
            , MedianamikControlInfo? pMedianamikControlSettings
            , Guid pDataTypeId
            , int pFlags)
            : this(Guid.NewGuid()
            , pName
            , pMaxLength
            , pMinLength
            , pTypeID
            , pHaveTooltip
            , pIsLanguageNeutral
            , pAllowsNull
            , pIsUnique
            , pValidationRegex
            , pGroupName
            , pMedianamikControlID
            , pMedianamikControlSettings
            , pDataTypeId)

        { }


        #endregion

        public string Name
        {
            get;
            set;
        }

        public string GetLocalizedName(CultureInfo cultureInfo)
        {
            return (string)System.Web.HttpContext.GetGlobalResourceObject("TypeManagement", ID + "_Label", cultureInfo);
        }

        public string Description { get; set; }

        public Guid ID
        {
            get;
            internal set;
        }

        public Guid TypeID
        {
            get;
            internal set;
        }

        public NodeType NodeType
        {
            get
            {
                return NodeTypeManager.GetNodeType(TypeID);
            }
        }

        public bool HaveTooltip
        {
            get;
            set;
        }

        public bool IsLanguageNeutral
        {
            get;
            set;
        }

        public bool IsRequired
        {
            get;
            set;

        }

        public bool IsGenerated { get; set; }

        public bool IsDeleted { get; internal set; }

        public Guid? MedianamikControlID
        {
            get;
            set;
        }

        public Guid? PrimaryMedianamikControlID
        {
            get;
            set;
        }

        public Guid? PrimaryTypeID
        {
            get;
            set;
        }

        public Guid? PrimaryPropertyID
        {
            get;
            set;
        }

        public string LocalizedName
        {
            get
            {
                if (!IsNew)
                {
                    return (string)System.Web.HttpContext.GetGlobalResourceObject("TypeManagement", ID + "_Label");
                }

                return string.Empty;
            }
        }

        public string GroupName
        {
            get;
            set;
        }

        public bool IsLookup
        {
            get
            {
                return PrimaryPropertyID.HasValue;
            }
        }

        public bool IsManyToMany
        {
            get
            {
                // À la question: Une propriété sans NodeType - dont le type de noeud n'existe pas - n'est certainement pas une propriété Many-To-Many? Max à répondu: Vrai 02/05/2011
                if (NodeType == null)
                    return false;
                return NodeType.GetManyToManyRelations().Any(p => p.RightRelation.ForeignPropertyID == ID);
            }
        }

        private NodeTypePropertyRelationship _relationship;
        public NodeTypePropertyRelationship Relationship
        {
            get
            {
                if (_relationship != NodeTypePropertyRelationship.ManyToMany && IsManyToMany)
                {
                    _relationship = NodeTypePropertyRelationship.ManyToMany;
                }
                else if(_relationship != NodeTypePropertyRelationship.OneToMany
                    && _relationship != NodeTypePropertyRelationship.ManyToOne && IsLookup)
                {
                    _relationship = NodeTypePropertyRelationship.OneToMany;
                }

                return _relationship;
            }
            set { _relationship = value; }
        }

        public Type GetType(bool nullable)
        {
            return DataUtil.GetCSharpType(this, nullable);
        }

        private MedianamikControl _medianamikControl;
        public MedianamikControl MedianamikControl
        {
            get
            {
                if (_medianamikControl == null && MedianamikControlID.HasValue)
                {
                    _medianamikControl = ConfigManager.GetMedianamikControl(MedianamikControlID.Value);
                }

                return _medianamikControl;
            }
            internal set
            {
                _medianamikControl = value;
            }
        }

        public MedianamikControlInfo MedianamikControlInfo
        {
            get;
            set;
        }

        public MedianamikControlInfo PrimaryMedianamikControlInfo
        {
            get;
            set;
        }

        public bool IsUnique
        {
            get;
            set;
        }

        private bool? _isUrl;
        public bool IsUrl
        {
            get
            {
                if (!_isUrl.HasValue)
                    _isUrl = ID.Equals(MedianamikProperties.Url);

                return _isUrl.GetValueOrDefault();
            }
        }

        public Regex ValidationRegex
        {
            get;
            set;
        }

        internal BitVector32 Flags;
        //{
        //    get;
        //     set;
        //}

        public bool Indexable
        {
            get
            {
                return Flags[(int)NodeTypePropertyFlag.Indexable];
            }
            set
            {
                Flags[(int)NodeTypePropertyFlag.Indexable] = value;
            }
        }

        private Guid _dataTypeId;
        public Guid DataTypeId
        {
            get { return _dataTypeId; }
        }

        private DataType _dataType;
        public DataType DataType
        {
            get
            {
                if (_dataType == null && _dataTypeId != null)
                {
                    _dataType = ConfigManager.GetDataTypeById(_dataTypeId);
                }
                return _dataType;
            }
        }

        private Guid? _primaryDataTypeId;
        private DataType _primaryDataType;
        public DataType PrimaryDataType
        {
            get
            {
                if (_primaryDataType == null && _primaryDataTypeId.HasValue)
                {
                    _primaryDataType = ConfigManager.GetDataTypeById(_primaryDataTypeId.Value);
                }
                return _primaryDataType;
            }
        }

        public short? MaxLength
        {
            get;
            set;
        }

        public short? MinLength
        {
            get;
            set;
        }

        public bool IsNew
        {
            get;
            internal set;
        }

        private RoleCollection _roles;
        public RoleCollection Roles
        {
            get
            {
                return _roles
                    ?? (_roles = new RoleCollection());
            }
            set
            {
                _roles = value;
            }
        }

        public IMedianamikControl GetMedianamikControl(bool pEnableClientScriptValidation,
            CultureInfo culture, string validationGroupName, bool hideNeutralLanguageIndication)
        {
            return GetMedianamikControl(pEnableClientScriptValidation, true,
                true, String.Empty, String.Empty, false, hideNeutralLanguageIndication, culture, validationGroupName);
        }

        public IMedianamikControl GetMedianamikControl(bool pEnableClientScriptValidation,
            bool pAutoGenerateValidators, CultureInfo culture)
        {
            return GetMedianamikControl(pEnableClientScriptValidation, pAutoGenerateValidators,
                true, String.Empty, String.Empty, false, false, culture);
        }

        protected RelationOptionCollection GetOptions(CultureInfo pCulture)
        {
            return NodeManager.GetRelationOptions(NodeType.GetOneToManyRelations().First(r => r.ForeignPropertyID.Equals(ID))
                        , pCulture.Name, null, MedianamikControlInfo.TreeRootNodeID);
        }

        public IMedianamikControl GetMedianamikControl(bool pEnableClientScriptValidation,
            bool pAutoGenerateValidators,
            bool pDisplayLabel, string pLabel, string pLabelExtensionText,
            bool hideMultiLingualControls, bool hideNeutralLanguageIndication, CultureInfo culture)
        {
            return GetMedianamikControl(pEnableClientScriptValidation, pAutoGenerateValidators,
                pDisplayLabel, pLabel, pLabelExtensionText, hideMultiLingualControls,hideNeutralLanguageIndication, culture, null);
        }

        public IMedianamikControl GetMedianamikControl(bool pEnableClientScriptValidation,
            bool pAutoGenerateValidators,
            bool pDisplayLabel, string pLabel, string pLabelExtensionText,
            bool hideMultiLingualControls, bool hideNeutralLanguageIndication, CultureInfo culture, string validationGroupName)
        {
            var medianamikControl = MedianamikControl.CreateInstance();

            medianamikControl.SetLoadEventHandler((sender, args) =>
            {
                medianamikControl.DisplayLabel = pDisplayLabel;
                medianamikControl.AutoGenerateValidators = pAutoGenerateValidators;
                medianamikControl.EnableClientScriptValidation = pEnableClientScriptValidation;

                if (pDisplayLabel)
                {
                    medianamikControl.Label = pLabel;
                    medianamikControl.LabelExtensionText = pLabelExtensionText;
                }

                if (pAutoGenerateValidators && !String.IsNullOrEmpty(validationGroupName))
                {
                    medianamikControl.ValidationGroupName = validationGroupName;
                }

                medianamikControl.HaveTooltip = HaveTooltip;
                medianamikControl.ControlInfo = MedianamikControlInfo;
                medianamikControl.ValidationExpression = (ValidationRegex == null) ?
                    String.Empty : ValidationRegex.ToString();
                medianamikControl.PropertyName = Name;
                medianamikControl.IsRequired = IsRequired;
                medianamikControl.IsUnique = IsUnique;
                medianamikControl.NodeTypePropertyId = ID;
                medianamikControl.NodeTypeId = NodeType.ID;
                medianamikControl.TypeName = NodeType.Name;
                medianamikControl.HideMultiLingualControls = hideMultiLingualControls;
                medianamikControl.HideNeutralLanguageIndication = hideNeutralLanguageIndication;
                medianamikControl.MaxLength = MaxLength;
                medianamikControl.IsLanguageNeutral = IsLanguageNeutral;
            });

            if (IsLookup)
            {
                medianamikControl.OptionsDelegate = () => GetOptions(culture);
            }

            return medianamikControl;
        }
    }

    public enum NodeTypePropertyFlag
    {
        Indexable = 1
    }
}
